package org.jmc.refmanager.web.wicket.page.admin;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.form.validation.EqualPasswordInputValidator;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.jmc.refmanager.domain.model.OrgUnit;
import org.jmc.refmanager.domain.model.Role;
import org.jmc.refmanager.domain.model.User;
import org.jmc.refmanager.domain.service.OrgUnitManager;
import org.jmc.refmanager.domain.service.RoleManager;
import org.jmc.refmanager.domain.service.UserManager;
import org.jmc.refmanager.domain.service.exception.BusinessException;
import org.jmc.refmanager.jsr303validators.JSR303FormValidator;
import org.jmc.refmanager.security.SecurityHelper;
import org.jmc.refmanager.web.wicket.enumeration.RoleEnum;
import org.jmc.refmanager.web.wicket.markup.html.form.ChoiceRenderer.DirectionChoiceRenderer;
import org.jmc.refmanager.web.wicket.page.template.TemplatePage;
import org.springframework.security.authentication.encoding.PasswordEncoder;

/**
 */
@AuthorizeInstantiation(value={"ROLE_ADMIN", "ROLE_APPROVER"})
public class UserAddPage extends TemplatePage {
	@SpringBean(name="orgUnitManager")
	private OrgUnitManager orgUnitManager;
	
	@SpringBean(name="userManager")
	private UserManager userManager;

	@SpringBean(name="roleManager")
	private RoleManager roleManager;

	@SpringBean(name = "passwordEncoder")
	private PasswordEncoder passwordEncoder;

	private DropDownChoice<OrgUnit> scope;
	
	/**
	 * 
	 */
	public UserAddPage() {
		super();
		setDefaultModel(new CompoundPropertyModel<User>(new User()));

		add(new Label("pageTitle", "Création d'un utilisateur"));
		UserCreateForm form = new UserCreateForm("formUserCreate", 
				(IModel<User>) getDefaultModel());
		add(form);

		this.scope = new DropDownChoice<OrgUnit>("validationScope", 
				new LoadableDetachableModel<List<OrgUnit>>() {
					private static final long serialVersionUID = 1L;

					@Override
					protected List<OrgUnit> load() {
						if (SecurityHelper.isAdministrator()) {
							return orgUnitManager.listDirections();
						} else {
							String matricule = SecurityHelper.getAuthentication().getName();
							User connectedUser = userManager.getByMatricule(matricule);

							List<OrgUnit> directions = new ArrayList<OrgUnit>();
							directions.add(connectedUser.getValidationScope());
							return directions;
						}
					}
		}, new DirectionChoiceRenderer<OrgUnit>());
		form.add(this.scope);

		final FeedbackPanel feedback = new FeedbackPanel("feedback",
        		new ComponentFeedbackMessageFilter(form));
		add(feedback);
	}

	/**
	 * 
	 * Formulaire de recherche
	 *
	 */
	final class UserCreateForm extends Form<User> {
		private static final long serialVersionUID = 1L;
		
		private String confirmPassword;
		
		public UserCreateForm(String id, IModel<User> model) {
			super(id, model);
			
			RequiredTextField<String> matricule = new RequiredTextField<String>("matricule");
			add(matricule);
			
			PasswordTextField password = new PasswordTextField("password");
			password.setRequired(true);
			// Evite que le mot de passe soit vid� en cas d'erreur sur onSubmit
			password.setResetPassword(false);
			add(password);

			// Mot de passe � confirmer
			// N'appartient au model du form => red�finition d'un mod�le local au formulaire
			PasswordTextField confirmPassword = new PasswordTextField("confirmPassword", 
					new PropertyModel<String>(this, "confirmPassword"));
			confirmPassword.setRequired(true);
			// Evite que le mot de passe soit vid� en cas d'erreur sur onSubmit
			confirmPassword.setResetPassword(false);
			add(confirmPassword);
			
			add(new EqualPasswordInputValidator(password, confirmPassword));
			
			DropDownChoice<Role> roleSelect = new DropDownChoice<Role>("role", new LoadableDetachableModel<List<Role>>() {
				private static final long serialVersionUID = 1L;

				@Override
				protected List<Role> load() {
					List<Role> roles = roleManager.findAll();
					return roles;
				}
			}, new IChoiceRenderer<Role>() {
				private static final long serialVersionUID = 1L;

				@Override
				public Object getDisplayValue(Role role) {
					return role.getDescription();
				}

				@Override
				public String getIdValue(Role role, int index) {
					return String.valueOf(role.getId());
				}
			})	{
				private static final long serialVersionUID = 1L;

				/* (non-Javadoc)
				 * @see org.apache.wicket.markup.html.form.DropDownChoice#onSelectionChanged(java.lang.Object)
				 */
				@Override
				protected void onSelectionChanged(Role newSelection) {
					super.onSelectionChanged(newSelection);
					String roleName = newSelection.getName();
					// Si le r�le est ROLE_ADMIN il n'y a pas de port�e � d�finir
					if (RoleEnum.ROLE_ADMIN.name().equals(roleName)) {
						scope.setVisible(false);
						scope.setRequired(false);
					} else {
						scope.setVisible(true);
						scope.setRequired(true);
					}
				}

				/* (non-Javadoc)
				 * @see org.apache.wicket.markup.html.form.DropDownChoice#wantOnSelectionChangedNotifications()
				 */
				@Override
				protected boolean wantOnSelectionChangedNotifications() {
					return true;
				}
			};
			
			roleSelect.setRequired(true);
			add(roleSelect);
			
	        add(new Button("btnCancel") {
	        	private static final long serialVersionUID = 1L;
	        	@Override
	        	public void onSubmit() {
					// Affiche le message sur la page redirig�e
	        		getSession().warn("L'utilisateur n'a pas été créé");
                    setResponsePage(UserFindPage.class);
                }
	        }.setDefaultFormProcessing(false));
	        
	        add(new Button("btnCreate") {
				private static final long serialVersionUID = 1L;

				/* (non-Javadoc)
				 * @see org.apache.wicket.markup.html.form.Button#onSubmit()
				 */
				@Override
				public void onSubmit() {
					try {
						User user = (User) getForm().getModelObject();
						
						String clearPassword = user.getPassword();
						String encodedPassword = passwordEncoder.encodePassword(clearPassword, null);
						user.setPassword(encodedPassword);
						
						user.setEnabled(true);
						user.setInitialized(true);
						
						userManager.persist(user);
					
						// Affiche le message sur la page redirig�e
						getSession().info("L'utilisateur a été créé avec succès");
						setResponsePage(UserFindPage.class);
					} catch (ConstraintViolationException e) {
						error("L'utilisateur n'a pas pu être créé");
						Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
						for (ConstraintViolation<?> constraintViolation : violations) {
							error(constraintViolation.getMessage());
						}
						setResponsePage(UserAddPage.this);
					} catch (BusinessException be) {
						error(be.getMessage());
						setResponsePage(UserAddPage.this);
					}
				}
	        });
	        
	        add(new JSR303FormValidator());
		}

		/**
		 * @param confirmPassword the confirmPassword to set
		 */
		public void setConfirmPassword(String confirmPassword) {
			this.confirmPassword = confirmPassword;
		}

		/**
		 * @return the confirmPassword
		 */
		public String getConfirmPassword() {
			return confirmPassword;
		}

	}
}

